﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using cocos2d;
using Microsoft.Xna.Framework;
using CampaignWP7.Base;

namespace CampaignWP7
{
    public class BunnyPlayer:CCSprite
    {
        public enum BunnyPlayerState
        {
            BPS_MOVING = 0x01,
            BPS_NORMAL = 0x02,                                            
            BPS_SHOOTING  = 0x04,

            
            BPS_DEAD = 0x08,

            BPS_NUM = 4
        }
        public enum MovingDir { MovDir_UP, MovDir_Down,MovDir_Stay };
        public MovingDir MovDir { set; get; }
        public BulletEmitter Weapon { get; set; }
        private CCPoint WeaponPosOffset { set; get; }
        public BunnyPlayerState CurrentState { set; get; }
        public float MoveFloorSpeed { set; get; }
        public float WeaponTimeCounter { set; get; }
        public float TouchTimer { set; get; }
        public float width { set; get; }
        public float height { set; get; }
        public static int CurrentScore { set; get; }
        public static int KillingNum { set; get; }
        public float ShootAnimationTime { set; get; }

        private CollideBox m_Collide;
        
        
        //
        enum AnimationType { AT_NORMAL = 0, AT_SHOOT,/* AT_HAPPYSHOOT,*/ AT_NUM }      
        protected static string[] ActionsName = { "relax", "shoot", "happyshoot" };
        protected static int[] ActionsFrameCount = { 3, 5, 1 };
        protected static Dictionary<string, List<CCSpriteFrame>> m_framesDict;
        private static string bunnyTextureName = "bunny";
        
        //
        public BunnyPlayer()
        {
            InitFramesDict();
            //
            Reset();
            //

            anchorPoint = new CCPoint(0.5f, 0.5f);
            position = new CCPoint(GameLayerLayout.PlayerPole,GameLayerLayout.PlayerMaxHigh);
            ResDef.g_BunnyBatchNode.addChild(this);

        }
        public void Shoot()
        {
            if (Weapon.CanEmit(WeaponTimeCounter) && CurrentState != BunnyPlayerState.BPS_SHOOTING)
            {
                PlayShootAnimation(WeaponTimeCounter);
            }
        }
        public void Reset()
        {
            WeaponTimeCounter = 0;
            MoveFloorSpeed = 250.0f;
            TouchTimer = 0;
            KillingNum = 0;
            CurrentScore = 0;
            CurrentState = BunnyPlayerState.BPS_NORMAL;
            MovDir = MovingDir.MovDir_Stay;

            Weapon = new BulletEmitter();
            Weapon.Reset();
            WeaponPosOffset = new CCPoint(45,30);
            ShootAnimationTime = 0.26f;
            Weapon.DelayTime = ShootAnimationTime;
            //
            string initName = bunnyTextureName + "_" + ActionsName[0] + "_0.png";
            bool ret = initWithSpriteFrameName(initName);
            CCSpriteFrame frame = CCSpriteFrameCache.sharedSpriteFrameCache().spriteFrameByName(initName);
            width = frame.Rect.size.width;
            height = frame.Rect.size.height;
            //
            position = new CCPoint(GameLayerLayout.PlayerPole, GameLayerLayout.PlayerMaxHigh);

            m_Collide = new CollideBox(new Vector2(-width, height), new Vector2(width,-height));
            m_Collide.SetPos(new Vector2(position.x, position.y));

        }
        //
        public override void update(float dt)
        {
            base.update(dt);
            //
            WeaponTimeCounter = WeaponTimeCounter + dt;
            TouchTimer = TouchTimer + dt;
            Weapon.position = new CCPoint(position.x + WeaponPosOffset.x, 
                                           position.y + WeaponPosOffset.y);

            if (m_Collide != null)
            {
                m_Collide.SetPos(new Vector2(position.x, position.y));
            }
            
        }
        //
        public void PlayShootAnimation(float dt)
        {
            if (CurrentState == BunnyPlayerState.BPS_SHOOTING) return;
            //
            CurrentState = BunnyPlayerState.BPS_SHOOTING;
            //
            List<CCFiniteTimeAction> acs = new List<CCFiniteTimeAction>();

            List<CCSpriteFrame> temp = m_framesDict[ActionsName[(int)AnimationType.AT_SHOOT]];
            CCAnimation ani = CCAnimation.animationWithFrames(temp);
            CCAnimate action = CCAnimate.actionWithDuration(ShootAnimationTime, ani, true);
            acs.Add(action);
            CCFiniteTimeAction weaponaction = CCCallFuncND.actionWithTarget(this, 
                                                    new SEL_CallFuncND(callbackShootEnd), dt);
            acs.Add(weaponaction);
            CCAction shoot = CCSequence.actions(acs.ToArray());
            shoot.tag = (int)CurrentState;
            //
            runAction(shoot);
            //
        }
        private void callbackShootEnd(CCNode sender, object data)
        {
            float dt = (float)data;
            Weapon.Emit(dt);
            WeaponTimeCounter = 0;
            TouchTimer = 0;
            PlayReleaxAnimation();
        }
        //
        public void PlayReleaxAnimation()
        {
            //
            stopActionByTag((int)CurrentState);
            //
            CurrentState = BunnyPlayerState.BPS_NORMAL;
            //
            List<CCSpriteFrame> temp = m_framesDict[ActionsName[(int)AnimationType.AT_NORMAL]];
            CCAnimation ani = CCAnimation.animationWithFrames(temp);
            CCAnimate action = CCAnimate.actionWithDuration(2.0f, ani, true);
            CCRepeatForever releax = CCRepeatForever.actionWithAction(action);

            releax.tag = (int)CurrentState;
            runAction(releax);
        }
        //
        public void PlayMoveToPos(CCPoint pos)
        {
            if (pos.y > GameLayerLayout.PlayerMaxHigh) pos.y = GameLayerLayout.PlayerMaxHigh;
            if (pos.y < GameLayerLayout.PlayerMinHigh) pos.y = GameLayerLayout.PlayerMinHigh;
            //
            int t =(int) (CurrentState & BunnyPlayerState.BPS_MOVING);
            if( t > 0)
            {
                ////逻辑，如果玩家再次点击的地方和元方向相反的话，则，取消上次的动画，并且停止移动
                MovingDir md = MovingDir.MovDir_Stay;
                if (pos.y - position.y > 0)
                {
                    md = MovingDir.MovDir_UP;
                }
                else if (pos.y - position.y < 0)
                {
                    md = MovingDir.MovDir_Down;
                }
                //
                if (md != MovDir)
                {
                    // 清除这两种移动的动画           
                    stopActionByTag((int)(BunnyPlayerState.BPS_NORMAL|BunnyPlayerState.BPS_MOVING));
                    stopActionByTag((int)(BunnyPlayerState.BPS_SHOOTING | BunnyPlayerState.BPS_MOVING));
                    //                   
                    CurrentState = CurrentState & ~BunnyPlayerState.BPS_MOVING;
                    return;
                }
                //
                return;
            }
            
           
            //
            float dest = pos.y - position.y;
            if (dest > 0) MovDir = MovingDir.MovDir_UP;
            else if (dest < 0) MovDir = MovingDir.MovDir_Down;
            else { MovDir = MovingDir.MovDir_Stay; return; }
            float dtime = Math.Abs(dest) / MoveFloorSpeed;
            if (dtime < 0.001f) return;

            //
            List<CCFiniteTimeAction> acs = new List<CCFiniteTimeAction>();     

            CCFiniteTimeAction moveaction = CCMoveTo.actionWithDuration(dtime, pos);
            acs.Add(moveaction);
            CCFiniteTimeAction callaction = CCCallFuncND.actionWithTarget(this, 
                                                new SEL_CallFuncND(callbackMoveToFloor), this);
            acs.Add(callaction);
            CCAction move = CCSequence.actions(acs.ToArray());

            //
            CurrentState = BunnyPlayerState.BPS_MOVING | CurrentState;
            //
            move.tag = (int)CurrentState;
            runAction(move);
   
        }
        //
        private void callbackMoveToFloor(CCNode sender, object data)
        {
            CurrentState = CurrentState & ~BunnyPlayerState.BPS_MOVING;
            MovDir = MovingDir.MovDir_Stay;
            PlayReleaxAnimation();
        }



        //
        private static void InitFramesDict()
        {
            if (m_framesDict == null || m_framesDict.Count == 0)
            {
                m_framesDict = new Dictionary<string, List<CCSpriteFrame>>();
                for (int i = 0; i < (int)AnimationType.AT_NUM; ++i)
                {
                    List<CCSpriteFrame> temp = new List<CCSpriteFrame>();
                    //---
                    //every animation type shouldn't greater then N!
                    //---
                    for (int k = 0; k < ActionsFrameCount[i]; ++k)
                    {
                        string frameName = ActionsName[i];
                        //the format of name likes  "bullet_normal_1.png"
                        frameName = bunnyTextureName + "_" + frameName + "_" + k + ".png";
                        CCSpriteFrame spriteframe = CCSpriteFrameCache.sharedSpriteFrameCache().spriteFrameByName(frameName);
                        if (spriteframe != null)
                        {
                            temp.Add(spriteframe);
                        }
                        //
                        if (k == ActionsFrameCount[i] - 1)
                        {
                            if (temp.Count != 0)
                            {
                                m_framesDict.Add(ActionsName[i], temp);
                            }
                            break;
                        }
                    }
                }
            }
        }

        public bool Intersects(CollideCircle bulletKeypoint, bool justByCenter)
        {
            bool bHit = false;
            if (justByCenter)
            {
                bHit = m_Collide.Intersects(bulletKeypoint.center);
            }
            else
            {
                bHit = m_Collide.Intersects(bulletKeypoint);
            }

            return bHit;
        }

        public void HitPlayer()
        {
            CurrentState = BunnyPlayerState.BPS_DEAD;
        }

    }
}
